home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir31 / vtsrc12b.zip / LIB / SONGELEM.PAS < prev    next >
Pascal/Delphi Source File  |  1993-03-21  |  18KB  |  562 lines

  1. UNIT SongElements;
  2.  
  3. INTERFACE
  4.  
  5. USES Objects;
  6.  
  7.  
  8.  
  9.  
  10. {----------------------------------------------------------------------------}
  11. { Definitions for handling the format of individual notes.                   }
  12. { Notes are composed of four fields:                                         }
  13. {                                                                            }
  14. {   Period:     A number in the range 0..2047 which states the period of     }
  15. {               the note in units of 1/3584000 per sample. (this is a        }
  16. {               somewhat empyric number. If anyone knows the exact Amiga     }
  17. {               number, please, tell us). A zero means to keep using the     }
  18. {               same period used before.                                     }
  19. {   Instrument: A number in range 0..63 meaning the number of the instrument }
  20. {               which will be used for the note. A zero means use the same.  }
  21. {   Command:    A number (no real range) of the way the note should be       }
  22. {               played (i.e. Vibrato) a change in the playing sequence (i.e. }
  23. {               pattern break) or a change in the general parameters of the  }
  24. {               module player (i.e. set tempo). All the possible values are  }
  25. {               defined in the TModCommand enumerated type below.            }
  26. {   Parameter:  A parameter for the command. Its meaning differs from one    }
  27. {               command to another. Sometimes each nibble is considered as a }
  28. {               different parameter.                                         }
  29. {____________________________________________________________________________}
  30.  
  31. TYPE
  32.   TModCommand = (
  33.                  mcNone,       { 0 00 } { Just play the note, without any special option. }
  34.  
  35.                  mcArpeggio,   { 0 xy } { Rotate through three notes rapidly. }
  36.                  mcTPortUp,    { 1 xx } { Tone Portamento Up:   Gradual change of tone towards high frequencies. }
  37.                  mcTPortDown,  { 2 xx } { Tone Portamento Down: Gradual change of tone towards low  frequencies. }
  38.                  mcNPortamento,{ 3 xy } { Note Portamento:      Gradual change of tone towards a given note.     }
  39.                  mcVibrato,    { 4 xy } { Vibrato: Frequency changes around the note. }
  40.                  mcT_VSlide,   { 5 xy } { Tone Port. Up + Volume slide: Parameter means vol. slide. }
  41.                  mcVib_VSlide, { 6 xy } { Vibrato       + Volume slide: Parameter means vol. slide. }
  42.                  mcTremolo,    { 7 xy } { Tremolo: I don't know for sure. Fast volume variations, I think. }
  43.                  mcNPI1,       { 8 xx } { Do Nothing (as far as I know). }
  44.                  mcSampleOffs, { 9 xx } { Start the sample from the middle. }
  45.                  mcVolSlide,   { A xy } { Volume slide: Gradual change in volume. }
  46.                  mcJumpPattern,{ B xx } { End pattern and continue from a different pattern sequence position. }
  47.                  mcSetVolume,  { C xx } { Set the volume of the sound. }
  48.                  mcEndPattern, { D xx } { Continue at the start of the next pattern. }
  49.                  mcExtended,   { E xy } { Extended set of commands (ProTracker). }
  50.                  mcSetTempo,   { F xx } { Set the tempo of the music, in 1/50ths of a second. }
  51.  
  52.                  mcSetFilter,  { E 0x } { Set the output filter to the on or off value. }
  53.                  mcFinePortaUp,{ E 1x } { Like TPortUp,   but slower. }
  54.                  mcFinePortaDn,{ E 2x } { Like TPortDown, but slower. }
  55.                  mcGlissCtrl,  { E 3x } { ¿?¿?¿? }
  56.                  mcVibCtrl,    { E 4x } { Set the vibrato waveform. }
  57.                  mcFineTune,   { E 5x } { Fine tune the frequency of the sound. }
  58.                  mcJumpLoop,   { E 6x } { Make a loop inside a pattern. }
  59.                  mcTremCtrl,   { E 7x } { Set the tremolo waveform (I think). }
  60.                  mcNPI2,       { E 8x } { Do Nothing (as far as I know). }
  61.                  mcRetrigNote, { E 9x } { ¿?¿?¿? }
  62.                  mcVolFineUp,  { E Ax } { Like VolSlide, but slower and towards high frequencies. }
  63.                  mcVolFineDown,{ E Bx } { Like VolSlide, but slower and towards low  frequencies. }
  64.                  mcNoteCut,    { E Cx } { ¿?¿?¿? }
  65.                  mcNoteDelay,  { E Dx } { Wait a little before starting note. }
  66.                  mcPattDelay,  { E Ex } { ¿?¿?¿? }
  67.                  mcFunkIt,     { E Fx } { No idea, but sounds funny. }
  68.  
  69.                  mcOktArp,     {      } { Oktalizer arpeggio  }
  70.                  mcOktArp2,    {      } { Oktalizer arpeggio2 }
  71.  
  72.                  mcLast
  73.   );
  74.  
  75. TYPE
  76.   PNoCommandNote = ^TNoCommandNote;
  77.   TNoCommandNote = RECORD
  78.     Instrument : BYTE;
  79.     Period     : WORD;
  80.     Volume     : BYTE;
  81.   END;
  82.  
  83.   PCommandNote = ^TCommandNote;
  84.   TCommandNote = RECORD
  85.     Command    : TModCommand;
  86.     Parameter  : BYTE;
  87.   END;
  88.  
  89.   PFullNote = ^TFullNote;
  90.   TFullNote = RECORD
  91.     CASE BYTE OF
  92.       0 : ( Instrument : BYTE;
  93.             Period     : WORD;
  94.             Volume     : BYTE;
  95.             Command    : TModCommand;
  96.             Parameter  : BYTE        );
  97.       1 : ( Note : TNoCommandNote;
  98.             Comm : TCommandNote      );
  99.   END;
  100.  
  101.  
  102.  
  103.  
  104. {----------------------------------------------------------------------------}
  105. { Definitions for handling the instruments used in the module.               }
  106. { Instruments are fragments of sampled sound (long arrays of bytes which     }
  107. { describe the wave of the sound of the instrument). The samples used in     }
  108. { music modules have a default volume and also, they can have a loop (for    }
  109. { sustained instruments) and a fine tuning constant (not yet implemented).   }
  110. {____________________________________________________________________________}
  111.  
  112. CONST
  113.   MaxSample      = 65520;
  114.   MaxInstruments = 255;
  115.  
  116.   LowQuality : BOOLEAN = TRUE;
  117.  
  118.   { Properties }
  119.  
  120.   ipMonoFreq = $0001;  { Set if the instrument is played always at the same freq (not implemented). }
  121.   ipLong     = $0002;  { Set if the instrument's sample is longer than 65520 bytes.                 }
  122.  
  123. TYPE
  124.   PSample = ^TSample;
  125.   TSample = ARRAY[0..MaxSample-1] OF SHORTINT;
  126.  
  127.   TIProperties = WORD; { Properties of the instrument. }
  128.  
  129.   PInstrumentRec = ^TInstrumentRec;
  130.   TInstrumentRec =
  131.     RECORD
  132.       Len,                  { Length of the instrument's sampled image.                           }
  133.       Reps,                 { Starting offset of the repeated portion.                            }
  134.       Repl  : LONGINT;      { Size of the repeated portion.                                       }
  135.       Vol   : BYTE;         { Default volume of the instrument (0..64)                            }
  136.       Ftune : BYTE;         { Fine tuning value for the instrument (not yet implemented).         }
  137.       NAdj  : WORD;         { Numerator of note adjutment.                                        }
  138.       DAdj  : WORD;         { Denominator of note adjutment.                                      }
  139.       Data  : ^TSample;     { Pointer to the first  65520 bytes of the sample.                    }
  140.       Xtra  : ^TSample;     { Pointer to the second 65520 bytes of the sample (if there is such). }
  141.       Prop  : TIProperties; { Bit mapped properties value.                                        }
  142.     END;
  143.  
  144.   PInstrument = ^TInstrument;
  145.   TInstrument =
  146.     OBJECT(TObject)
  147.       Name  : PString;
  148.       Instr : PInstrumentRec;
  149.  
  150.       CONSTRUCTOR Init;
  151.       DESTRUCTOR  Done; VIRTUAL;
  152.  
  153.       PROCEDURE FreeContents;
  154.       PROCEDURE Desample;
  155.  
  156.       PROCEDURE Change(Instrument : PInstrumentRec);
  157.       FUNCTION  GetName                             : STRING;
  158.       PROCEDURE SetName(S: STRING);
  159.     END;
  160.  
  161.  
  162.  
  163.  
  164. {----------------------------------------------------------------------------}
  165. { Definitions for handling the tracks of which patterns are built.           }
  166. { Tracks are lists of notes and command values of which the empty leading    }
  167. { and trailing blanks have been removed (obviated).                          }
  168. {____________________________________________________________________________}
  169.  
  170. TYPE
  171.   PNoteTrack = ^TNoteTrack;
  172.   TNoteTrack =
  173.     RECORD
  174.       NoteOffset : BYTE;
  175.       NumNotes   : BYTE;
  176.       Notes      : ARRAY[0..255] OF TNoCommandNote;
  177.     END;
  178.  
  179.   PCommTrack = ^TCommTrack;
  180.   TCommTrack =
  181.     RECORD
  182.       NoteOffset : BYTE;
  183.       NumNotes   : BYTE;
  184.       Notes      : ARRAY[0..255] OF TCommandNote;
  185.     END;
  186.  
  187.   PFullTrack = ^TFullTrack;
  188.   TFullTrack = ARRAY[0..255] OF TFullNote;
  189. {
  190.   PTrackCache = ^TTrackCache;
  191.   TTrackCache =
  192.     RECORD
  193.       InUse    : BOOLEAN;
  194.       Modified : BOOLEAN;
  195.       LastUse  : WORD;
  196.       Track    : PFullTrack;
  197.     END;
  198.  
  199. VAR
  200.   TrackCaches = ARRAY[1..MaxChannels] OF TTrackCache;
  201. }
  202. TYPE
  203.   PTrack = ^TTrack;
  204.   TTrack =
  205.     OBJECT(TObject)
  206.       Name : PString;
  207.       Note : PNoteTrack;
  208.       Comm : PCommTrack;
  209.  
  210.       CONSTRUCTOR Init;
  211.       DESTRUCTOR  Done; VIRTUAL;
  212.  
  213.       PROCEDURE FreeContents;
  214.  
  215.       PROCEDURE ChangeNote(At: WORD; VAR FullNote: TFullNote);
  216.       PROCEDURE GetNote   (At: WORD; VAR FullNote: TFullNote);
  217.  
  218.       PROCEDURE GetFullTrack(VAR Track: TFullTrack);
  219.       PROCEDURE SetFullTrack(VAR Track: TFullTrack);
  220.  
  221.       FUNCTION GetName : STRING;
  222.     END;
  223.  
  224.  
  225.  
  226.  
  227. {----------------------------------------------------------------------------}
  228. { Definitions for handling the format of the patterns.                       }
  229. { Patterns are arrays of pointers to tracks (up to 12 tracks).               }
  230. { A music module can have up to 255 individual patterns, arranged in a       }
  231. { sequence of up to 255.                                                     }
  232. { Empty patterns are not counted.                                            }
  233. {____________________________________________________________________________}
  234.  
  235. CONST
  236.   MaxSequence     = 256;
  237.   MaxPatterns     = 256;
  238.   MaxPatternLines = 256;
  239.   MaxChannels     = {10}16;
  240.  
  241. TYPE
  242.   PPatternRec = ^TPatternRec;
  243.   TPatternRec =
  244.     RECORD
  245.       NNotes   : BYTE;
  246.       NChans   : BYTE;
  247.       Tempo    : BYTE;
  248.       BPM      : BYTE;
  249.       Channels : ARRAY[1..MaxChannels] OF WORD;
  250.     END;
  251.  
  252.   PPattern = ^TPattern;
  253.   TPattern =
  254.     OBJECT(TObject)
  255.       Name : PString;
  256.       Patt : PPatternRec;
  257.  
  258.       CONSTRUCTOR Init(Chans: WORD);
  259.       DESTRUCTOR  Done; VIRTUAL;
  260.  
  261.       PROCEDURE FreeContents;
  262.  
  263.       FUNCTION GetName : STRING;
  264.     END;
  265.  
  266.   PPatternSequence = ^TPatternSequence;
  267.   TPatternSequence = ARRAY[1..MaxSequence] OF BYTE;
  268.  
  269.  
  270.  
  271.  
  272. {----------------------------------------------------------------------------}
  273. { General definitions for the song.                                          }
  274. {____________________________________________________________________________}
  275.  
  276. TYPE
  277.   PSongComment = ^TSongComment;
  278.   TSongComment = ARRAY[1..16] OF STRING[60];
  279.  
  280.  
  281.  
  282.  
  283. IMPLEMENTATION
  284.  
  285. USES Heaps;
  286.  
  287.  
  288.  
  289. {----------------------------------------------------------------------------}
  290. { TInstrument object implementation.                                         }
  291. {____________________________________________________________________________}
  292.  
  293. CONSTRUCTOR TInstrument.Init;
  294.   BEGIN
  295.     TObject.Init;
  296.   END;
  297.  
  298.  
  299. DESTRUCTOR TInstrument.Done;
  300.   BEGIN
  301.     SetName('');
  302.     FreeContents;
  303.     TObject.Done;
  304.   END;
  305.  
  306.  
  307. PROCEDURE TInstrument.FreeContents;
  308.   BEGIN
  309.     IF Instr = NIL THEN EXIT;
  310.     IF Instr^.Len > 65520 THEN
  311.       BEGIN
  312.         FullHeap.HFreeMem(POINTER(Instr^.Xtra), Instr^.Len - 65520);
  313.         Instr^.Len := 65520;
  314.       END;
  315.  
  316.     FullHeap.HFreeMem(POINTER(Instr^.Data), Instr^.Len);
  317.     FullHeap.HFreeMem(POINTER(Instr), SizeOf(Instr^));
  318.   END;
  319.  
  320.  
  321. PROCEDURE TInstrument.Change(Instrument : PInstrumentRec);
  322.   BEGIN
  323.     FreeContents;
  324.     IF Instrument <> NIL THEN
  325.       BEGIN
  326.         FullHeap.HGetMem(POINTER(Instr), SizeOf(Instr^));
  327.         IF Instr <> NIL THEN
  328.           BEGIN
  329.             Move(Instrument^, Instr^, SizeOf(Instr^));
  330.             IF Instr^.NAdj = 0 THEN
  331.               BEGIN
  332.                 Instr^.NAdj := $2000;
  333.                 Instr^.DAdj := $2000;
  334.               END;
  335.             IF LowQuality THEN
  336.               Desample;
  337.           END;
  338.       END;
  339.   END;
  340.  
  341. FUNCTION TInstrument.GetName : STRING;
  342.   BEGIN
  343.     IF Name <> NIL THEN
  344.       GetName := Name^
  345.     ELSE
  346.       GetName := '';
  347.   END;
  348.  
  349.  
  350. PROCEDURE TInstrument.Desample;
  351.   VAR
  352.     w        : WORD;
  353.     p        : POINTER;
  354.     SizeFree : WORD;
  355.   BEGIN
  356.     WITH Instr^ DO
  357.       IF (Instr <> NIL) AND (Instr^.Data <> NIL)        AND
  358.          (Len > 128) AND ((Repl >= 2000) OR (Repl = 0)) THEN
  359.         BEGIN
  360.           FOR w := 0 TO Len DIV 2 - 1 DO
  361.             Data^[w] := (INTEGER(Data^[w*2]) +
  362.                          INTEGER(Data^[w*2+1])) DIV 2;
  363.  
  364.           p := Ptr(SEG(Data^), OFS(Data^) + Len DIV 2 + 7);
  365.           p := Ptr(SEG(p^) + (OFS(p^) SHR 4), OFS(p^) AND $8);
  366.  
  367.           SizeFree := Len -
  368.                       (WORD((SEG(p^) - SEG(Data^)) SHL 4) +
  369.                        WORD( OFS(p^) - OFS(Data^))        );
  370.  
  371.           FullHeap.HFreeMem(p, SizeFree);
  372.  
  373.           Len  := Len  DIV 2;
  374.           Reps := Reps DIV 2;
  375.           Repl := Repl DIV 2;
  376.           NAdj := NADJ  *  2;
  377.         END;
  378.   END;
  379.  
  380.  
  381.  
  382. PROCEDURE TInstrument.SetName(S: STRING);
  383.   BEGIN
  384.     IF Name <> NIL THEN
  385.       FullHeap.HDisposeStr(Name);
  386.  
  387.     IF S <> '' THEN
  388.       Name := FullHeap.HNewStr(S);
  389.   END;
  390.  
  391.  
  392.  
  393. {----------------------------------------------------------------------------}
  394. { TTrack object implementation.                                              }
  395. {____________________________________________________________________________}
  396.  
  397. CONSTRUCTOR TTrack.Init;
  398.   BEGIN
  399.     TObject.Init;
  400.   END;
  401.  
  402.  
  403. DESTRUCTOR TTrack.Done;
  404.   BEGIN
  405.     FullHeap.HDisposeStr(Name);
  406.     FreeContents;
  407.     TObject.Done;
  408.   END;
  409.  
  410.  
  411. PROCEDURE TTrack.FreeContents;
  412.   BEGIN
  413.     IF Note <> NIL THEN
  414.       FullHeap.HFreeMem(POINTER(Note), Note^.NumNotes*SizeOf(TNoCommandNote) + 2);
  415.     IF Comm <> NIL THEN
  416.       FullHeap.HFreeMem(POINTER(Comm), Comm^.NumNotes*SizeOf(TCommandNote)   + 2);
  417.   END;
  418.  
  419.  
  420. PROCEDURE TTrack.ChangeNote(At: WORD; VAR FullNote: TFullNote);
  421.   VAR
  422.     Track : TFullTrack;
  423.   BEGIN
  424.     GetFullTrack(Track);
  425.     Track[At] := FullNote;
  426.     SetFullTrack(Track);
  427.   END;
  428.  
  429.  
  430. PROCEDURE TTrack.GetFullTrack(VAR Track: TFullTrack);
  431.   VAR
  432.     i : WORD;
  433.   BEGIN
  434.     FillChar(Track, SizeOf(Track), 0);
  435.  
  436.     IF Note <> NIL THEN
  437.       FOR i := 0 TO Note^.NumNotes DO
  438.         Track[i+Note^.NoteOffset].Note := Note^.Notes[i];
  439.  
  440.     IF Comm <> NIL THEN
  441.       FOR i := 0 TO Note^.NumNotes DO
  442.         Track[i+Note^.NoteOffset].Note := Note^.Notes[i];
  443.   END;
  444.  
  445.  
  446. PROCEDURE TTrack.SetFullTrack(VAR Track: TFullTrack);
  447.   VAR
  448.     i     : WORD;
  449.     MNote : TNoteTrack;
  450.     MComm : TCommTrack;
  451.   BEGIN
  452.     FillChar(MNote, SizeOf(MNote), 0);
  453.     FillChar(MComm, SizeOf(MComm), 0);
  454.     FOR i := 0 TO 255 DO
  455.       BEGIN
  456.         IF (Track[i].Instrument = 0) AND
  457.            (Track[i].Period     = 0) AND
  458.            (Track[i].Volume     = 0) THEN
  459.           BEGIN
  460.             IF MNote.NoteOffset = i THEN
  461.               INC(MNote.NoteOffset);
  462.           END
  463.         ELSE
  464.           BEGIN
  465.             MNote.NumNotes := i - MNote.NoteOffset + 1;
  466.             MNote.Notes[i - MNote.NoteOffset] := Track[i].Note;
  467.           END;
  468.  
  469.         IF Track[i].Command = mcNone THEN
  470.           BEGIN
  471.             IF MComm.NoteOffset = i THEN
  472.               INC(MComm.NoteOffset);
  473.           END
  474.         ELSE
  475.           BEGIN
  476.             MComm.NumNotes := i - MComm.NoteOffset + 1;
  477.             MComm.Notes[i - MComm.NoteOffset] := Track[i].Comm;
  478.           END;
  479.       END;
  480.  
  481.     FreeContents;
  482.  
  483.     FullHeap.HGetMem(POINTER(Note), MNote.NumNotes*SizeOf(TNoCommandNote) + 2);
  484.     FullHeap.HGetMem(POINTER(Comm), MComm.NumNotes*SizeOf(TCommandNote)   + 2);
  485.  
  486.     IF Note <> NIL THEN
  487.       Move(MNote, Note^, MNote.NumNotes*SizeOf(TNoCommandNote) + 2);
  488.     IF Comm <> NIL THEN
  489.       Move(MComm, Comm^, MComm.NumNotes*SizeOf(TCommandNote)   + 2);
  490.   END;
  491.  
  492.  
  493. PROCEDURE TTrack.GetNote(At: WORD; VAR FullNote: TFullNote);
  494.   BEGIN
  495.     DEC(At);
  496.     FillChar(FullNote, SizeOf(FullNote), 0);
  497.  
  498.     IF (Note <> NIL) AND (At >= Note^.NoteOffset) AND
  499.        (At < Note^.NoteOffset + Note^.NumNotes)   THEN
  500.       FullNote.Note := Note^.Notes[At - Note^.NoteOffset];
  501.  
  502.     IF (Comm <> NIL) AND (At >= Comm^.NoteOffset) AND
  503.        (At < Comm^.NoteOffset + Comm^.NumNotes)   THEN
  504.       FullNote.Comm := Comm^.Notes[At - Comm^.NoteOffset];
  505.   END;
  506.  
  507.  
  508. FUNCTION TTrack.GetName : STRING;
  509.   BEGIN
  510.     IF Name <> NIL THEN
  511.       GetName := Name^
  512.     ELSE
  513.       GetName := '';
  514.   END;
  515.  
  516.  
  517.  
  518.  
  519. {----------------------------------------------------------------------------}
  520. { TPattern object implementation.                                            }
  521. {____________________________________________________________________________}
  522.  
  523. CONSTRUCTOR TPattern.Init(Chans: WORD);
  524.   BEGIN
  525.     TObject.Init;
  526.  
  527.     FullHeap.HGetMem(POINTER(Patt), Chans*2 + 4);
  528.  
  529.     IF Patt <> NIL THEN
  530.       FillChar(Patt^, Chans*2 + 4, 0);
  531.     Patt^.NChans := Chans;
  532.   END;
  533.  
  534.  
  535. DESTRUCTOR TPattern.Done;
  536.   BEGIN
  537.     FullHeap.HDisposeStr(Name);
  538.     FreeContents;
  539.     TObject.Done;
  540.   END;
  541.  
  542.  
  543. PROCEDURE TPattern.FreeContents;
  544.   BEGIN
  545.     IF Patt <> NIL THEN
  546.       FullHeap.HFreeMem(POINTER(Patt), Patt^.NChans*2 + 4);
  547.   END;
  548.  
  549.  
  550. FUNCTION TPattern.GetName : STRING;
  551.   BEGIN
  552.     IF Name <> NIL THEN
  553.       GetName := Name^
  554.     ELSE
  555.       GetName := '';
  556.   END;
  557.  
  558.  
  559.  
  560.  
  561. END.
  562.